using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Security.Permissions;
using System.Text;
using System.Query;

namespace PowerStructure
{
<<<<<<< .mine

    public interface ParameterizedIIdProvider {
      IComparable Id(Type type);
   }

=======
    public interface ParameterizedIIdProvider
    {
        IComparable Id(Type obj);
    }
    
>>>>>>> .theirs
    public interface IId {
      IComparable Id {get; set;}
   }
    
    public interface IDisplayName {
      IComparable DisplayName {get; }
   }

    public static class Utils2
    {
        public static IEnumerablePropertyDescriptor view(this IEnumerable list)
        {
            return new IEnumerablePropertyDescriptor(list);
        }
    }
    
    public class FullExpandableObjectConverter : ExpandableObjectConverter
    {
        public PropertyDescriptorCollection GetProperties2(ITypeDescriptorContext context, object value, Attribute[] attributes)
        {
            return base.GetProperties(context, value, attributes);
        }
        public override bool GetPropertiesSupported(ITypeDescriptorContext context)
        {
            return true;
        }
        public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
        {
            PropertyDescriptorCollection myCollection = new PropertyDescriptorCollection(base.GetProperties(context, value, attributes).OfType<PropertyDescriptor>().ToArray());
            foreach (PropertyDescriptor pd in myCollection)
            {
                if (typeof(IList).IsAssignableFrom(pd.PropertyType) || (pd.PropertyType.IsGenericType && typeof(IList<>).IsAssignableFrom(pd.PropertyType.GetGenericTypeDefinition() )))
                {
                    myCollection.Remove(pd);
                    IEnumerable ienum = value.GetType().GetProperty(pd.Name).GetValue(value, null) as IEnumerable ;
                    myCollection.Add(new GenericPropertyDescriptor<IEnumerablePropertyDescriptor>(new IEnumerablePropertyDescriptor(ienum ), pd.Name));
                }
            }
            return myCollection;
        }
    }

    public class GenericPropertyDescriptor<T> : PropertyDescriptor
    {
        T _data;
        IComparable _title = "";
        
        public GenericPropertyDescriptor(T obj) : base(obj.ToString(), null)
        {
            _data = obj;
        }
        public GenericPropertyDescriptor(T obj, string title) : base(title, null)
        {
            _data = obj;
            _title = title;
        }        
        public override AttributeCollection Attributes
        {
            get
            {
                return new AttributeCollection(null);
            }
        }
        public override bool CanResetValue(object component)
        {
            return true;
        }
        public override Type ComponentType
        {
            get
            {
                return typeof(T);
            }
        }
        public override string DisplayName
        {
            get
            {
                if(_title as string == "" && (_data as IDisplayName) != null)
                    _title = (_data as IDisplayName).DisplayName;
                if(_title as string == "" && (_data as IId) != null)
                    _title = (_data as IId).Id;
                return _title.ToString();
            }
        }
        public override string Description
        {
            get
            {
                return "description";
            }
        }
        public override object GetValue(object component)
        {
            return (object)_data;
        }
        public override bool IsReadOnly
        {
            get { return true; }
        }
        public override string Name
        {
            get { return "name"; }
        }
        public override Type PropertyType
        {
            get { return typeof(T); }
        }
        public override void ResetValue(object component) { }
        public override bool ShouldSerializeValue(object component)
        {
            return true;
        }
        public override void SetValue(object component, object value)
        {
        }
    }

    [TypeConverter(typeof(FullExpandableObjectConverter ))]
    public class IEnumerablePropertyDescriptor : ICustomTypeDescriptor
    {
        IEnumerable _t;
        public IEnumerablePropertyDescriptor(IEnumerable t)
        {
            _t = t;
        }
        #region ICustomTypeDescriptor Members

        public String GetClassName()
        {
            return TypeDescriptor.GetClassName(this, true);
        }

        public System.ComponentModel.AttributeCollection GetAttributes()
        {
            return TypeDescriptor.GetAttributes(this, true);
        }

        public String GetComponentName()
        {
            return TypeDescriptor.GetComponentName(this, true);
        }

        public TypeConverter GetConverter()
        {
            return TypeDescriptor.GetConverter(this, true);
        }

        public EventDescriptor GetDefaultEvent()
        {
            return TypeDescriptor.GetDefaultEvent(this, true);
        }

        public PropertyDescriptor GetDefaultProperty()
        {
            return TypeDescriptor.GetDefaultProperty(this, true);
        }

        public object GetEditor(Type editorBaseType)
        {
            return TypeDescriptor.GetEditor(this, editorBaseType, true);
        }

        public EventDescriptorCollection GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(this, attributes, true);
        }

        public EventDescriptorCollection GetEvents()
        {
            return TypeDescriptor.GetEvents(this, true);
        }

        public object GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }

        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            return GetProperties();
        }

        #endregion

        public PropertyDescriptorCollection GetProperties()
        {
            PropertyDescriptorCollection pds = new PropertyDescriptorCollection(null);
            foreach (object obj in _t)
            {
                Type pdctor = typeof(GenericPropertyDescriptor<>).MakeGenericType(new Type[] { obj.GetType() });
                object pd = pdctor.GetConstructor(new Type[] { obj.GetType() }).Invoke(new object[] { obj });
                pds.Add((PropertyDescriptor)pd);
            }
            return pds;
        }
    }

    //public class IEnumerableTypeDescriptionProvider : TypeDescriptionProvider
    //{
    //    public IEnumerableTypeDescriptionProvider(TypeDescriptionProvider parent) : base(parent) { }

    //    public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
    //    {
    //        return new IEnumerablePropertyDescriptor(instance as IEnumerable);
    //    }
    //}


    ///// <summary>
    ///// This is our custom provider. It simply provides a custom type descriptor
    ///// and delegates all its other tasks to its parent 
    ///// </summary>
    //public class UselessTypeDescriptionProvider : TypeDescriptionProvider
    //{
    //    /// <summary>
    //    /// Constructor
    //    /// </summary>
    //    public UselessTypeDescriptionProvider(TypeDescriptionProvider parent)
    //        : base(parent)
    //    {
    //    }

    //    /// <summary>
    //    /// Create and return our custom type descriptor and chain it with the original 
    //    /// custom type descriptor
    //    /// </summary>
    //    public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
    //    {
    //        return new UselessCustomTypeDescriptor(base.GetTypeDescriptor(objectType, instance));
    //    }
    //}

    ///// <summary>
    ///// This is our custom type descriptor. It creates a new property and returns it along
    ///// with the original list
    ///// </summary>
    //public class UselessCustomTypeDescriptor : CustomTypeDescriptor
    //{
    //    /// <summary>
    //    /// Constructor
    //    /// </summary>
    //    public UselessCustomTypeDescriptor(ICustomTypeDescriptor parent)
    //        : base(parent)
    //    {
    //    }

    //    /// <summary>
    //    /// This method add a new property to the original collection
    //    /// </summary>
    //    public override PropertyDescriptorCollection GetProperties()
    //    {
    //        // Enumerate the original set of properties and create our new set with it
    //        PropertyDescriptorCollection originalProperties = base.GetProperties();
    //        List<PropertyDescriptor> newProperties = new List<PropertyDescriptor>();
    //        foreach (PropertyDescriptor pd in originalProperties) newProperties.Add(pd);

    //        // Create a new property and add it to the collection
    //        PropertyDescriptor newProperty = TypeDescriptor.CreateProperty(typeof(object), "UselessProperty", typeof(string));
    //        newProperties.Add(newProperty);

    //        // Finally return the list
    //        return new PropertyDescriptorCollection(newProperties.ToArray(), true);
    //    }
    //}
}
